package graphics.effects.particles;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;

import org.lwjgl.opengl.GL11;

import graphics.system.Color;
import graphics.system.GLTools;
import graphics.system.TextureContainer;
import graphics.system.VertexBufferObject;
import graphics.system.VertexBufferObject.Drawmode;
import tools.Floatmath;
import tools.Point;
public class Particlesystem {
	private final static float TWOPI = Floatmath.PI * 2;
	private PSysSetting pset;
	private Vector<Particle> parts;
	private int maxparts;
	private VertexBufferObject vbo;
	private float dt;
	private int texid;
	private class Particle {
		public Point pos, vel;
		public Color col;
		public long stime, ltime;
		private float angle;
		private float size;
		private float ssize;
		public float avel;
		public Particle(Point pos, Point vel, float avel, Color c, long lt, float size) {
			this.pos = pos;
			this.vel = vel;
			col = c;
			angle = Floatmath.radToDeg(TWOPI * Floatmath.random());
			ssize = size;
			this.size = size;
			this.avel = avel;
			stime = System.currentTimeMillis();
			ltime = Math.max(1, lt);
		}
		public float getProgress(long currenttime) {
			return (float) (currenttime - stime) / (float) ltime;
		}
	}
	public Particlesystem(PSysSetting set, int maxparts, float dt) {
		pset = set;
		this.maxparts = maxparts;
		this.dt = dt;
		parts = new Vector<Particle>();
		switch (pset.dmode) {
			case POINTS : {
				vbo = new VertexBufferObject(Drawmode.POINTS);
				break;
			}
			case LINES : {
				vbo = new VertexBufferObject(Drawmode.LINES);
				break;
			}
			case TEXFACE : {
				this.texid = TextureContainer.getTexture(pset.texname).getTexID();
				break;
			}
		}
	}
	public void emitParticle(Point pos, Point vel, int amount) {
		if (parts.size() + amount > maxparts) {
			amount = maxparts - parts.size();
		}
		for (int i = 0; i < amount; i++) {
			addParticle(pos, vel);
		}
	}
	private void addParticle(Point pos, Point vel) {
		Particle p = new Particle(new Point(pos.x, pos.y), vel.rotate(pset.randdir * TWOPI * (Floatmath.random() - 0.5f)), (((Floatmath.random() - 0.5f) * pset.randavel) * pset.avel), pset.scolor, pset.lifetime + (long) ((Floatmath.random() - 0.5f) * (float) pset.randomtime), pset.size);
		parts.add(p);
	}
	public void draw() {
		switch (pset.dmode) {
			case POINTS : {
				Point pos[] = new Point[parts.size()];
				Color cols[] = new Color[parts.size()];
				for (int i = 0; i < parts.size(); i++) {
					pos[i] = parts.get(i).pos;
					cols[i] = parts.get(i).col;
				}
				if (pos.length > 0) {
					vbo.updateVerts(pos);
					vbo.setColorInfo(cols);
					GL11.glPointSize(10);
					vbo.draw();
				}
				break;
			}
			case LINES : {
				Point pos[] = new Point[parts.size() * 2];
				Color cols[] = new Color[parts.size() * 2];
				for (int i = 0; i < parts.size(); i++) {
					pos[i * 2] = parts.get(i).pos;
					pos[i * 2 + 1] = parts.get(i).pos.add(parts.get(i).vel.mul(dt * -parts.get(i).size));
					cols[i * 2] = parts.get(i).col;
					cols[i * 2 + 1] = parts.get(i).col.mul(0.1f);
				}
				if (pos.length > 0) {
					vbo.updateVerts(pos);
					vbo.setColorInfo(cols);
					vbo.draw();
				}
				break;
			}
			case TEXFACE : {
				for (int i = 0; i < parts.size(); i++) {
					GLTools.drawTexRect(parts.get(i).pos.x, parts.get(i).pos.y, parts.get(i).size, parts.get(i).size, parts.get(i).angle, texid, parts.get(i).col);
				}
				break;
			}
		}
	}
	public int getNumParts() {
		return parts.size();
	}
	public void handle() {
		long ct = System.currentTimeMillis();
		float prog;
		for (int i = 0; i < parts.size(); i++) {
			Particle p = parts.get(i);
			prog = p.getProgress(ct);
			if (prog >= 1 || p.col.a <= 0.01f || p.size <= 0) {
				parts.remove(i);
				i--;
			}
			else {
				p.pos.sAdd(p.vel.mul(dt));
				p.vel.sAdd(pset.gravity);
				if (pset.alignangle) {
					p.angle = Floatmath.radToDeg(p.vel.angle()) + 90;
				}
				else {
					p.angle += p.avel * dt;
				}
				p.col = pset.getColor(prog);
				p.size = p.ssize * (1 - (prog * pset.shrinkspeed));
			}
		}
	}
}
